#define _GNU_SOURCE
#include <string.h>

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "http.h"
#undef _GNU_SOURCE

#define HTTP_GET "GET %s HTTP/1.1\r\nHost: %s\r\nKeep-Alive: 300\r\nConnection: keep-alive\r\n\r\n"
#define HTTP_POST "POST %s HTTP/1.1\r\nHost: %s\r\nContent-Length: %d\r\nContent-Type: text/html\r\nKeep-Alive: 300\r\nConnection: keep-alive\r\n\r\n%s\r\n"

//TODO replay strstr to some function can specify length
//pack decode. return <0 means malform, set headlen & packlen & scodep
int http_depack(const char *buf, int buflen, int * headlenp, int * packlenp, int *scodep)
{
	assert(buf && headlenp && packlenp && scodep);

	double version;

	if (buflen == 0) return 1;

	if (*packlenp > 0) return 2;	

	/* scode */
	if (*scodep == 0 && sscanf(buf, "HTTP/%lf %d[^ ]", &version, scodep) <= 0) {
		return -1;
	}

	const char * p;
	if (*headlenp > 0) {
		goto CHUNK;
	}

	/* head */
	p = strstr(buf, "\r\n\r\n");
	if (!p) {
		return 0;
	}
	*headlenp = p - buf + 4;

	if (*scodep != 200 && *headlenp == buflen) {
		*packlenp = buflen;
		return 0;
	}

	/* Content-length */ 
	int content_len;
	p = strcasestr(buf, "Content-Length:");
	if (p == NULL) {
		goto CHUNK;
	}
	p += strlen("Content-Length:");
	
	if(sscanf(p, "%d\r\n", &content_len) < 0 || content_len < 0) {
		return -2;
	}

	*packlenp = *headlenp + content_len;
	return 0;

CHUNK:
	/* Chunk */
	if (*headlenp == buflen) return 3;

	if (strcasestr(buf, "Transfer-Encoding: chunked\r\n") 
		&& !strncmp(buf+buflen-5, "0\r\n\r\n", 5)) {
		*packlenp = buflen;
		return 0;
	}
	
	return 1;
}
int http_query_free(char * query)
{
	if(!query){
		return 1;
	}
	free(query);
	return 0;
}

char * http_query_new(const char * url, const char * vars, int * qlenp)
{
	assert(url);

	int url_len = strlen(url);
	int vars_len = 0;
	if(vars){
		vars_len = strlen(vars);
	}

	if(url_len == 0 || url_len > HTTP_URL_SIZE - 1){
		return NULL;
	}
	char host[HTTP_URL_SIZE];
	char path[HTTP_URL_SIZE];
	
	const char * start = strstr(url, "://");
	if (!start) {
		start = url;
		url_len -= start - url;
	} else {
		start += 3;
	}
	char * p = strstr(start, "/");
	if (!p) {
		strncpy(host, start, url_len);
		host[url_len] = 0;
		path[0] = '/';
		path[1] = '\0';
	} else {
		strncpy(host, start, p-start);
		host[p - start] = '\0';
		strncpy(path, p, url_len - (p - start));
		path[url_len - (p - start)] = '\0';
	}

	int header_len;
	if(vars_len > HTTP_VARS_SIZE - 1){
		return NULL;
	}else if(vars_len == 0){
		header_len = strlen(HTTP_GET) + url_len;
	}else{
		header_len = strlen(HTTP_POST) + url_len;
	}

	char * query = malloc(header_len + vars_len + 1);
	if(!query){
		return NULL;
	}
	if(vars_len == 0){
		*qlenp = snprintf(query, header_len + vars_len, HTTP_GET, path, host);
	}else{
		*qlenp = snprintf(query, header_len + vars_len, HTTP_POST, path, host, vars_len, vars);
	}
	return query;
}

#ifdef HTTP_MAIN
int main()
{
	char * url = "http://baidu.com:8080/baidu.html";
	int len;
	char * query = http_query_new(url, NULL, &len);
	printf("[%d]%s\n", len, query);
	return 0;
}
#endif
